package com.ly.auth.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ly.auth.entity.AuthGrantedAuthority;
import com.ly.auth.entity.OauthClientDetails;
import com.ly.auth.mapper.auth.OauthClientDetailsMapper;
import com.ly.common.core.model.LoginUser;
import com.ly.common.core.utils.JsonUtil;
import com.ly.common.core.utils.StringUtils;
import com.ly.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 自定义ClientDetailsService
 */
@Service
@Slf4j
public class CustomClientDetailsService implements ClientDetailsService {

    @Autowired
    private OauthClientDetailsMapper oauthClientDetailsMapper;

    @Autowired
    private RedisService redisService;

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        if (StringUtils.isEmpty(clientId)) {
            throw new RuntimeException("clientId不能为空!");
        }
        log.info("clientId [{}] 正在执行loadClientByClientId方法", clientId);
        BaseClientDetails clientDetails = new BaseClientDetails();
        OauthClientDetails oauthClientDetails = null;
        //先从缓存中获取ClientDetails信息
        String redisValue = redisService.getCacheObject(getClientDetailsKey(clientId));
        if (StringUtils.isNotEmpty(redisValue)) {
            oauthClientDetails = JsonUtil.toBean(redisValue, OauthClientDetails.class);
        }

        //OauthClientDetails oauthClientDetails = oauthClientDetailsMapper.selectByPrimaryKey(clientId);

        //redis中不存在则从数据库中查询
        if (Objects.isNull(oauthClientDetails)) {
            oauthClientDetails = oauthClientDetailsMapper.selectByPrimaryKey(clientId);
            if (Objects.isNull(oauthClientDetails)) {
                log.info("clientId [{}] 不存在!", clientId);
                throw new RuntimeException("clientId [" + clientId + "] 不存在!");
                //throw new ClientRegistrationException("clientId [" + clientId + "] 不存在!");
            }
            //从数据库中正确找到指定的client_id后，记录到缓存。发起一次获取code(4次)和token(5次)时，loadClientByClientId会被调用近十次。短时间缓存起来，避免重复查库
            redisService.setCacheObject(getClientDetailsKey(clientId), oauthClientDetails, 60L, TimeUnit.SECONDS);
        }

        clientDetails.setClientId(oauthClientDetails.getClientId());
        clientDetails.setClientSecret(oauthClientDetails.getClientSecret());
        clientDetails.setAccessTokenValiditySeconds(oauthClientDetails.getAccessTokenValidity());
        clientDetails.setRefreshTokenValiditySeconds(oauthClientDetails.getRefreshTokenValidity());
        clientDetails.setScope(getList(oauthClientDetails.getScope()));
        clientDetails.setResourceIds(getList(oauthClientDetails.getResourceIds()));
        clientDetails.setAuthorizedGrantTypes(getList(oauthClientDetails.getAuthorizedGrantTypes()));
        clientDetails.setAutoApproveScopes(getList(oauthClientDetails.getAutoapprove()));
        //设置可跳转地址
        clientDetails.setRegisteredRedirectUri(getSet(oauthClientDetails.getWebServerRedirectUri()));
        //设置补充信息
        clientDetails.setAdditionalInformation(getMap(oauthClientDetails.getAdditionalInformation(), oauthClientDetails.getClientId()));
        clientDetails.setAuthorities(getAuthGrantedAuthorities(oauthClientDetails.getAuthorities()));

        return clientDetails;
    }


    private List<String> getList(String str) {
        List<String> list = new ArrayList<>();
        if (StringUtils.isNotEmpty(str)) {
            list = new ArrayList<>(Arrays.asList(str.split(",")));
        }
        return list;
    }

    private Set<String> getSet(String str) {
        Set<String> set = new HashSet<>();
        if (StringUtils.isNotEmpty(str)) {
            set = new HashSet<>(Arrays.asList(str.split(",")));
        }
        return set;
    }

    private Map<String, Object> getMap(String str, String clientId) {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> map = new HashMap<>();
        try {
            if (StringUtils.isNotEmpty(str)) {
                map = mapper.readValue(str, new TypeReference<Map<String, Object>>() {});
            }
        } catch (JsonProcessingException e) {
            log.error("clientId [{}] 的配置信息中，additional_information数据格式错误，必须是标准的json字符串。", clientId);
        }
        return map;
    }

    private List<AuthGrantedAuthority> getAuthGrantedAuthorities(String str) {
        List<AuthGrantedAuthority> list = new ArrayList<>();
        if (StringUtils.isNotEmpty(str)) {
            for (String code : str.split(",")) {
                AuthGrantedAuthority authority = new AuthGrantedAuthority();
                authority.setCode(code);
                list.add(authority);
            }
        }
        return list;
    }

    private String getClientDetailsKey(String token) {
        return "client_details:" + token;
    }

}
